package com.jin.udp;

import com.jin.udp.bean.Client;
import com.jin.udp.bean.IbeaconDetail;
import com.jin.udp.util.GsonUtil;
import com.jin.udp.util.MqttSign;
import com.jin.udp.util.UDPUtils;
import org.eclipse.paho.mqttv5.client.IMqttToken;
import org.eclipse.paho.mqttv5.client.MqttClient;
import org.eclipse.paho.mqttv5.client.MqttConnectionOptions;
import org.eclipse.paho.mqttv5.client.persist.MemoryPersistence;
import org.eclipse.paho.mqttv5.common.MqttException;
import org.eclipse.paho.mqttv5.common.MqttMessage;
import org.eclipse.paho.mqttv5.common.MqttSecurityException;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName: MQTTThread
 * @Description:
 * @Author: 12071
 * @Date: 2021/7/7 19:12
 */
public class UploadThread extends Thread{
    /**
     * 是否继续监听 , 循环控制变量
     */
    boolean isReceive = true;

    /**
     * 存储发送数据的客户端信息
     */
    ArrayList<Client> clients = new ArrayList<>();

    /**
     * MQTT连接配置
     */
    String productKey = "a1ncMVrDuNy";
    String deviceName = "deviceTest1";
    String deviceSecret = "df40504966c96041b3350cc510c7a345";
    String postTopic = "/sys/" + productKey + "/" + deviceName + "/thing/event/property/post";

    @Override
    public void run() {
        super.run();

        //计算Mqtt建联参数
        MqttSign sign = new MqttSign();
        sign.calculate(productKey, deviceName, deviceSecret);

        //使用Paho连接阿里云物联网平台
        String port = "443";
        //您可登录物联网平台控制台，在实例概览页，找到并单击对应实例，进入实例详情页，查看实例终端节点
        String broker = "ssl://" + productKey + ".iot-as-mqtt.cn-shanghai.aliyuncs.com" + ":" + port;
        MemoryPersistence persistence = new MemoryPersistence();


        try {

            //Paho Mqtt 客户端
            MqttClient sampleClient = new MqttClient(broker, sign.getClientid(), persistence);

            //Paho Mqtt 连接参数
            MqttConnectionOptions connOpts = new MqttConnectionOptions();
            connOpts.setCleanStart(true);
            connOpts.setKeepAliveInterval(180);
            connOpts.setUserName(sign.getUsername());
            connOpts.setPassword(sign.getPassword().getBytes());

            //Paho Mqtt5 设备上报QoS1&QoS2消息流控
            connOpts.setReceiveMaximum(5);

            //Paho Mqtt5 设备接收的最大报文长度
            connOpts.setMaximumPacketSize(1024L);

            IMqttToken iMqttToken = sampleClient.connectWithResult(connOpts);
            System.out.println("broker: " + broker + " Connected");

            //I. 创建 DatagramSocket 对象 , 用于 UDP 数据包的发送和接收

            //1. UDP 数据包接收者 , 监听 9000 端口
            //      该 DatagramSocket 既可以接收数据包 , 也可以发送数据包
            DatagramSocket datagramSocket = new DatagramSocket(9000);
            //II. 接收 UDP 数据包 , 无限循环接收来自客户端的信息 , 并根据不同的信息进行不同处理
            while (isReceive) {

                //2. 接收数据包使用的缓冲区
                byte[] receiveBuffer = new byte[1024];
                //3. 接收 UDP 数据包使用的 DatagramPacket 对象
                DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);

                //4. 接收 UDP 数据包
                datagramSocket.receive(receivePacket);

                //5. 获取发送端的 IP 地址
                String sendIP = receivePacket.getAddress().getHostAddress();
                //6. 获取发送端的端口号
                int sendPort = receivePacket.getPort();
                //7. 获取接收到的数据的长度
                int receiveLen = receivePacket.getLength();
                //8. 获取接收到的数据 , 并转为字符串
                byte[] data = Arrays.copyOfRange(receivePacket.getData(), 0, receiveLen);
                String receiveData = UDPUtils.bytesToHexString(data);
                //  String receiveData = new String(receivePacket.getData(), 0, receiveLen);
                // 截取网关Mac和终端Mac:
                String stationMac = receiveData.substring(22, 34);
                String nodeMac = receiveData.substring(38, 50);
                Integer rssi = Integer.parseInt(receiveData.substring(50, 52), 16) - 255;
                Long receiveTime = System.currentTimeMillis();
                if (Receiver.stationMacs.stream().anyMatch(stationMac::equalsIgnoreCase) && Receiver.nodes.stream().anyMatch(nodeMac::equalsIgnoreCase)) {
                    //9. 信息封装，打印接收到的数据包信息
                    IbeaconDetail ibeaconDetail = new IbeaconDetail(nodeMac, stationMac, rssi, receiveTime);
                    System.out.println("服务器 接收到 " + sendIP + " : " + sendPort + " 发送的数据:  " + ibeaconDetail.toString());

                    //上传数据到物联网平台
                    String content = mqttPayload(ibeaconDetail);

                    MqttMessage message = new MqttMessage(content.getBytes());//
                    message.setQos(0);

                    sampleClient.publish(postTopic, message);
                    System.out.println("publish: " + content);
                }
                //退出服务器循环
                if ("exit".equals(receiveData)) {
                    isReceive = false;
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (MqttSecurityException e) {
            e.printStackTrace();
        } catch (MqttException e) {
            e.printStackTrace();
        } finally {
            System.out.println("服务器 运行结束");
        }
    }

    private String mqttPayload(IbeaconDetail ibeaconDetail){
        Map<String, Object> map = new HashMap<>();
        map.put("id","1");
        map.put("version","1.0");

        Map<String,IbeaconDetail> params = new HashMap<>();
        params.put("ibeaconInfo",ibeaconDetail);
        map.put("params", params);
        String payload = GsonUtil.bean2Json(map);
        return payload;
    }
}
